﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using T.FAS.Runtime.Metadata.Entity;

namespace T.FAS.Runtime.Action.Plugin
{
    public class DependencyManager
    {
        /// <summary>
        /// 获取当前元数据依赖谁
        /// </summary>
        /// <param name="metaDataContent"></param>
        /// <returns></returns>
        public static List<MetaDataDependency> GetMetaDataDependencys(IMetaDataContent metaDataContent)
        {
            var list = new List<MetaDataDependency>();
            var action = metaDataContent as ActionMetaData;
            if (action == null)
                return list;
            //Action类型，如果是CDO类型的Action，需要强依赖CDO元数据
            if (action.ActionType == ActionType.CDO)
            {
                if (!string.IsNullOrEmpty(action.RelatedMetaDataID))
                {
                    list.Add(new MetaDataDependency()
                    {
                        MetadataID = action.ID,
                        ParentMetadataID = action.RelatedMetaDataID,
                        DependencyType = MetaDataDependencyType.Strong
                    });
                }
            }
            if (action.MetaDependencys != null && action.MetaDependencys.Count > 0)
            {
                foreach (var item in action.MetaDependencys)
                {
                    if (!list.Exists(t => t.ParentMetadataID.Equals(item.DependencyMetaDataID)) && !string.IsNullOrEmpty(item.DependencyMetaDataID))
                    {
                        list.Add(new MetaDataDependency()
                        {
                            MetadataID = action.ID,
                            ParentMetadataID = item.DependencyMetaDataID,
                            DependencyType = MetaDataDependencyType.Strong
                        });
                    }
                }
            }
            //Aciton入参,如果不是基础类型的,需要依赖相关的元数据
            var inParams = action.MethodParams.FindAll(x => x.ParamType == ParamType.In);
            if (inParams != null && inParams.Count > 0)
            {
                inParams.ForEach(x =>
                {
                    if (x.ParamSourceType != ParamSourceType.Basic && x.ParamSourceType != ParamSourceType.UserDefine)
                    {
                        if (!list.Exists(t => t.ParentMetadataID.Equals(x.SourceID)))
                        {
                            if (!string.IsNullOrEmpty(x.SourceID))
                            {
                                list.Add(new MetaDataDependency()
                                {
                                    MetadataID = action.ID,
                                    ParentMetadataID = x.SourceID,
                                    DependencyType = MetaDataDependencyType.Strong
                                });
                            }
                        }
                    }
                });
            }
            //Action有出参时，如果参数不是基础类型的，需要依赖相关的元数据
            if (action.ReturnValueType != ReturnValueType.Void)
            {
                var outParams = action.MethodParams.FindAll(x => x.ParamType == ParamType.Out);
                if (outParams != null && outParams.Count > 0)
                {
                    outParams.ForEach(x =>
                    {
                        if (x.ParamSourceType != ParamSourceType.Basic && x.ParamSourceType != ParamSourceType.UserDefine)
                        {
                            if (!list.Exists(t => t.ParentMetadataID.Equals(x.SourceID)))
                            {
                                if (!string.IsNullOrEmpty(x.SourceID))
                                {
                                    list.Add(new MetaDataDependency()
                                    {
                                        MetadataID = action.ID,
                                        ParentMetadataID = x.SourceID,
                                        DependencyType = MetaDataDependencyType.Strong
                                    });
                                }
                            }
                        }
                    });
                }
            }
            /* Todo
            //Action有权限设置时，需要依赖相关的权限元数据
            if (action.ActionPermission != null)
            {
                if (action.ActionPermission.DataPermissionObject != null)
                {
                    //ToDo 对权限及操作的依赖
                }
            }
            */
            return list;
        }
        /// <summary>
        /// 当前元数据变更需要通知出去的变更信息(MetaUpdateType定义的枚举项,需要在这里处理)
        /// </summary>
        /// <param name="oldMetaData"></param>
        /// <param name="newMetaData"></param>
        /// <returns></returns>
        public static MetaDataUpdateSet GetMetaDataUpdateSet(IMetaDataContent oldMetaData, IMetaDataContent newMetaData)
        {
            var updateSet = new MetaDataUpdateSet();
            updateSet.UpdateItemList = new List<MetaDataUpdateItem>();
            if (oldMetaData.MetaDataCode != newMetaData.MetaDataCode)
            {
                MetaDataUpdateItem updateItem = new MetaDataUpdateItem();
                updateItem.UpdateType = MetaUpdateType.Item_Action_Code;
                updateItem.UpdateKey = "Code";
                updateItem.NewValue = newMetaData.MetaDataCode;
                updateItem.OldValue = oldMetaData.MetaDataCode;
                updateSet.UpdateItemList.Add(updateItem);
            }
            if (oldMetaData.MetaDataName != newMetaData.MetaDataName)
            {
                MetaDataUpdateItem updateItem = new MetaDataUpdateItem();
                updateItem.UpdateType = MetaUpdateType.Item_Action_Name;
                updateItem.UpdateKey = "Name";
                updateItem.NewValue = newMetaData.MetaDataName;
                updateItem.OldValue = oldMetaData.MetaDataName;
                updateSet.UpdateItemList.Add(updateItem);
            }
            var oldAction = oldMetaData as ActionMetaData;
            var newAction = newMetaData as ActionMetaData;
            if (oldAction != null && newAction != null)
            {
                //入参
                var oldAction_InParamList = oldAction.MethodParams.FindAll(p => p.ParamType == ParamType.In);
                var newAction_InParamList = newAction.MethodParams.FindAll(p => p.ParamType == ParamType.In);
                updateSet.UpdateItemList.AddRange(GetParamUpdateItems(oldAction_InParamList, newAction_InParamList, MetaUpdateType.Item_Action_InParam));

                //出参
                var oldAction_OutParamList = oldAction.MethodParams.FindAll(p => p.ParamType == ParamType.Out);
                var newAction_OutParamList = newAction.MethodParams.FindAll(p => p.ParamType == ParamType.Out);
                updateSet.UpdateItemList.AddRange(GetParamUpdateItems(oldAction_OutParamList, newAction_OutParamList, MetaUpdateType.Item_Action_OutParam));

                if (!oldAction.ReturnValueType.Equals(newAction.ReturnValueType))
                {
                    updateSet.UpdateItemList.Add(new MetaDataUpdateItem()
                    {
                        UpdateType = MetaUpdateType.Item_Action_ReturnType,
                        UpdateKey = "ActionReturnType",
                        NewValue = newAction.ReturnValueType,
                        OldValue = oldAction.ReturnValueType
                    });
                }
            }
            return updateSet;

        }
        /// <summary>
        /// 其他元数据变更通知到当前元数据,当前元数据对变更的响应逻辑
        /// </summary>
        /// <param name="metaDataContent"></param>
        /// <param name="updateSet"></param>
        /// <returns></returns>
        public static MetaUpdateResult UpdateDependencyMetaData(IMetaDataContent metaDataContent, MetaDataUpdateSet updateSet)
        {
            var action = metaDataContent as ActionMetaData;
            if (action == null)
                return null;
            if (updateSet != null && updateSet.UpdateItemList != null && updateSet.UpdateItemList.Count <= 0)
                return null;

            MetaUpdateResult result = new MetaUpdateResult();
            int failCount = 0;
            int successCount = 0;

            foreach (var item in updateSet.UpdateItemList)
            {
                bool isAutoFixChange = false;
                item.UpdateResult = true;
                try
                {
                    //CDO的Code改变会触发CDO下对应的Action元数据信息的变更
                    if (item.UpdateType == MetaUpdateType.Item_CompositeDataObject_MetaDataCode ||
                        item.UpdateType == MetaUpdateType.Item_CompositeDataObject_MetaDataName ||
                        item.UpdateType == MetaUpdateType.Item_DataObject_MetaDataCode ||
                        item.UpdateType == MetaUpdateType.Item_EntityObject_MetaDataCode ||
                        item.UpdateType == MetaUpdateType.Item_DataQuery_MetaDataCode)
                    {
                        //处理CDO自动生成的Aciton元数据：需要处理ActionMetaData、ActionMetaDataMethod
                        if (action.ActionType == ActionType.CDO && updateSet.MetaDataID.Equals(action.RelatedMetaDataID))
                        {
                            if (item.UpdateType == MetaUpdateType.Item_CompositeDataObject_MetaDataCode && action.Code.EndsWith(Convert.ToString(item.OldValue)))
                            {
                                //处理主表信息
                                if (!string.IsNullOrEmpty(action.Code))
                                {
                                    action.Code = action.Code.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                    isAutoFixChange = true;
                                }
                                if (!string.IsNullOrEmpty(action.Description))
                                {
                                    action.Description = action.Description.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                    isAutoFixChange = true;
                                }
                                //处理方法表信息
                                if (action.Method != null)
                                {
                                    if (!string.IsNullOrEmpty(action.Method.Code))
                                    {
                                        action.Method.Code = action.Method.Code.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                        isAutoFixChange = true;
                                    }
                                    if (!string.IsNullOrEmpty(action.Method.Description))
                                    {
                                        action.Method.Description = action.Method.Description.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                        isAutoFixChange = true;
                                    }
                                    if (!string.IsNullOrEmpty(action.Method.MethodContent))
                                    {
                                        action.Method.MethodContent = action.Method.MethodContent.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                        isAutoFixChange = true;
                                    }
                                    //ToDo CDO Action的执行前后事件的脚本处理
                                }
                            }
                            if (item.UpdateType == MetaUpdateType.Item_CompositeDataObject_MetaDataName)
                            {
                                if (!string.IsNullOrEmpty(action.Name))
                                {
                                    action.Name = action.Name.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                    isAutoFixChange = true;
                                }
                                if (action.Method != null)
                                {
                                    if (!string.IsNullOrEmpty(action.Method.Name))
                                    {
                                        action.Method.Name = action.Method.Name.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                        isAutoFixChange = true;
                                    }
                                    //ToDo CDO Action的执行前后事件的脚本处理
                                }
                            }
                        }
                        //针对参数的集中处理
                        if (item.UpdateType == MetaUpdateType.Item_CompositeDataObject_MetaDataCode)
                        {
                            //参数的变更处理
                            if (action.MethodParams != null && action.MethodParams.Count > 0)
                            {
                                var targetParams = action.MethodParams.FindAll(x => x.SourceID == updateSet.MetaDataID);
                                if (targetParams != null)
                                {
                                    targetParams.ToList().ForEach(t =>
                                    {
                                        if (!string.IsNullOrEmpty(t.Name))
                                        {
                                            t.Name = t.Name.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                            isAutoFixChange = true;
                                        }
                                        if (!string.IsNullOrEmpty(t.Description))
                                        {
                                            t.Description = t.Description.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                            isAutoFixChange = true;
                                        }
                                    });
                                }
                            }
                        }
                        else if (item.UpdateType == MetaUpdateType.Item_CompositeDataObject_MetaDataName)
                        {
                            //参数的变更处理
                            if (action.MethodParams != null && action.MethodParams.Count > 0)
                            {
                                var targetParams = action.MethodParams.FindAll(x => x.SourceID == updateSet.MetaDataID);
                                if (targetParams != null)
                                {
                                    targetParams.ToList().ForEach(t =>
                                    {
                                        if (!string.IsNullOrEmpty(t.SourceName) || !string.IsNullOrEmpty(t.ParamValueType))
                                        {
                                            t.SourceName = t.SourceName.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                            t.ParamValueType = t.ParamValueType.Replace(Convert.ToString(item.OldValue), Convert.ToString(item.NewValue));
                                            isAutoFixChange = true;
                                        }
                                    });
                                }
                            }
                        }
                        else if (item.UpdateType == MetaUpdateType.Item_EntityObject_MetaDataCode)
                        {
                            if (action.MethodParams != null && action.MethodParams.Count > 0)
                            {
                                var targetParams = action.MethodParams.FindAll(x => x.SourceID == updateSet.MetaDataID);
                                if (targetParams != null)
                                {
                                    targetParams.ToList().ForEach(t =>
                                    {
                                        if (!string.IsNullOrEmpty(t.SourceName) || !string.IsNullOrEmpty(t.ParamValueType))
                                        {
                                            t.SourceName = Convert.ToString(item.NewValue);
                                            t.ParamValueType = Convert.ToString(item.NewValue);
                                            isAutoFixChange = true;
                                        }
                                    });
                                }
                            }
                            if (action.DynamicFilterSourceID == updateSet.MetaDataID)
                            {
                                action.DynamicFilterSourceName = Convert.ToString(item.NewValue);
                            }
                            if (action.DynamicSortSourceID == updateSet.MetaDataID)
                            {
                                action.DynamicSortSourceName = Convert.ToString(item.NewValue);
                            }
                        }
                        else if (item.UpdateType == MetaUpdateType.Item_DataObject_MetaDataCode)
                        {
                            if (action.MethodParams != null && action.MethodParams.Count > 0)
                            {
                                var targetParams = action.MethodParams.FindAll(x => x.SourceID == updateSet.MetaDataID);
                                if (targetParams != null)
                                {
                                    targetParams.ToList().ForEach(t =>
                                    {
                                        if (!string.IsNullOrEmpty(t.SourceName) || !string.IsNullOrEmpty(t.ParamValueType))
                                        {
                                            t.SourceName = Convert.ToString(item.NewValue);
                                            t.ParamValueType = Convert.ToString(item.NewValue);
                                            isAutoFixChange = true;
                                        }
                                    });
                                }
                            }

                            if (action.DynamicFilterSourceID == updateSet.MetaDataID)
                            {
                                action.DynamicFilterSourceName = Convert.ToString(item.NewValue);
                            }
                            if (action.DynamicSortSourceID == updateSet.MetaDataID)
                            {
                                action.DynamicSortSourceName = Convert.ToString(item.NewValue);
                            }
                        }
                    }

                     /* Todo
                    //权限依赖处理
                    if (action.ActionPermission != null)
                    {
                        if (action.ActionPermission.DataPermissionObject != null)
                        {
                            //ToDo 对权限的依赖变更处理
                        }
                    }
                     */
                    if (isAutoFixChange)
                    {
                        item.UpdateResult = true;
                        successCount++;
                    }
                }
                catch (Exception ex)
                {
                    item.UpdateResult = false;
                    item.FailMessage = $"Action:{action.Code}针对元数据{updateSet.MetaDataCode}的{Convert.ToString(item.UpdateType)}的变更自动处理失败，失败原因：{ex.ToString()},请手动修复";
                    failCount++;
                }
            }
            if (failCount == 0 && successCount == 0)
            {
                result.UpdateState = UpdateState.SuccessWithNoUpdate;
            }
            else if (failCount == 0 && successCount > 0)
            {
                result.UpdateState = UpdateState.Success;
                action.MetaDataCode = action.Code;
                action.MetaDataName = action.Name;
            }
            else if (failCount > 0 && successCount == 0)
            {
                result.UpdateState = UpdateState.Fail;
            }
            else if (failCount > 0 && successCount > 0)
            {
                result.UpdateState = UpdateState.PartSuccess;
                action.MetaDataCode = action.Code;
                action.MetaDataName = action.Name;
            }
            return result;
        }
        private static MetaDataUpdateItem GetTargetUpdateItem(MetaDataUpdateSet updateSet, List<ActionMetaDataMethodParam> needAutoFixItems)
        {
            MetaDataUpdateItem targetUpdateItem = null;
            MetaUpdateType targetUpdateType = default;
            switch (needAutoFixItems[0].ParamSourceType)
            {
                case ParamSourceType.CDO:
                    {
                        targetUpdateType = MetaUpdateType.Item_CompositeDataObject_MetaDataName;
                    }
                    break;
                case ParamSourceType.DO:
                case ParamSourceType.SDO:
                    {
                        targetUpdateType = MetaUpdateType.Item_CompositeDataObject_MetaDataName;
                    }
                    break;
                case ParamSourceType.DQ:
                    {
                        targetUpdateType = MetaUpdateType.Item_DataQuery_MetaDataName;
                    }
                    break;
                case ParamSourceType.EO:
                    {
                        targetUpdateType = MetaUpdateType.Item_EntityObject_MetaDataName;
                    }
                    break;
                default:
                    return targetUpdateItem;
            }
            targetUpdateItem = updateSet.UpdateItemList.Find(u => u.UpdateType == targetUpdateType && u.OperateType == DependencyChangeType.Update);

            return targetUpdateItem; ;
        }

        private static List<MetaDataUpdateItem> GetParamUpdateItems(List<ActionMetaDataMethodParam> oldAction_ParamList, List<ActionMetaDataMethodParam> newAction_ParamList, MetaUpdateType updateType)
        {
            var list = new List<MetaDataUpdateItem>();
            if (oldAction_ParamList == null && newAction_ParamList == null)
                return list;
            bool needUpdate = false;
            if (oldAction_ParamList == null || newAction_ParamList == null)
            {
                needUpdate = true;
            }
            //如果参数个数不同，直接返回
            if (oldAction_ParamList.Count != newAction_ParamList.Count)
            {
                needUpdate = true;
            }
            //如果参数个数相同，需要按照参数顺序进行参数的Code、Name、类型的比较
            if (oldAction_ParamList.Count == newAction_ParamList.Count)
            {
                oldAction_ParamList = oldAction_ParamList.OrderBy(x => x.SortOrder).ToList();
                newAction_ParamList = newAction_ParamList.OrderBy(x => x.SortOrder).ToList();

                foreach (var newParam in newAction_ParamList)
                {
                    var oldParam = oldAction_ParamList.Find(x => x.SortOrder == newParam.SortOrder);
                    if (oldParam == null)
                    {
                        needUpdate = true;
                        break;
                    }
                    if (!ObjectsIsEqual(oldParam.Code, newParam.Code) ||
                        !ObjectsIsEqual(oldParam.Name, newParam.Name) ||
                        !ObjectsIsEqual(oldParam.ParamSourceType, newParam.ParamSourceType) ||
                        !ObjectsIsEqual(oldParam.ParamValueType, newParam.ParamValueType) ||
                        !ObjectsIsEqual(oldParam.SourceID, newParam.SourceID) ||
                        !ObjectsIsEqual(oldParam.SourceName, newParam.SourceName)
                        )
                    {
                        needUpdate = true;
                        break;
                    }
                }
            }
            if (needUpdate)
            {
                list.Add(new MetaDataUpdateItem()
                {
                    UpdateType = updateType,
                    UpdateKey = "ActionParam",
                    NewValue = newAction_ParamList,
                    OldValue = oldAction_ParamList
                });
            }
            return list;
        }
        private static bool ObjectsIsEqual(object data1, object data2)
        {
            if (data1 == null && data2 != null)
                return false;
            if (data1 != null && data2 == null)
                return false;
            if (data1 == null && data2 == null)
                return true;
            if (data1.Equals(data2))
                return true;
            else
                return false;

        }
    }
}
